package com.gitee.denger.mybatis.example.ext.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * from org.springframework.util.ReflectionUtils
 */
public abstract class SimpleReflectionUtils {

    /**
     * Invoke the given callback on all fields in the target class, going up the
     * class hierarchy to get all declared fields.
     *
     * @param clazz the target class to analyze
     * @param fc    the callback to invoke for each field
     */
    public static void doWithFields(Class<?> clazz, FieldCallback fc) {
        // Keep backing up the inheritance hierarchy.
        Class<?> targetClass = clazz;
        do {
            Field[] fields = targetClass.getDeclaredFields();
            for (Field field : fields) {
                try {
                    fc.doWith(field);
                } catch (Exception ex) {
                    throw new IllegalArgumentException("Not allowed to access field '" + field.getName() + "': " + ex);
                }
            }
            targetClass = targetClass.getSuperclass();
        }
        while (targetClass != null && targetClass != Object.class);
    }

    /**
     * 获取方法
     *
     * @param clazz      class
     * @param methodName 方法名
     * @return 方法
     */
    public static Method findMethod(Class<?> clazz, String methodName) {
        return findMethod(clazz, methodName, new Class<?>[0]);
    }


    /**
     * 获取方法
     *
     * @param clazz      class
     * @param methodName 方法名
     * @param paramTypes 参数类型
     * @return 方法
     */
    public static Method findMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) {
        try {
            return clazz.getMethod(methodName, paramTypes);
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException(clazz + "没有找到方法" + methodName, e);
        }
    }

    /**
     * 获取字段值
     *
     * @param clazz     class
     * @param target    实例对象
     * @param fieldName 字段名
     * @return 字段值
     */
    public static Object getField(Class<?> clazz, Object target, String fieldName) {
        try {
            Field field = clazz.getField(fieldName);
            return getField(field, target);
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
        }
    }


    /**
     * 获取字段值
     *
     * @param field  字段
     * @param target 实例对象
     * @return 字段值
     */
    public static Object getField(Field field, Object target) {
        if (null == field) {
            throw new IllegalArgumentException("参数field是null");
        }
        try {
            return field.get(target);
        } catch (IllegalAccessException e) {
            throw new IllegalArgumentException(e);
        }
    }

    /**
     * 获取方法
     *
     * @param clazz      class
     * @param target     实例对象
     * @param methodName 方法名
     * @return 方法
     */
    public static Object invokeMethod(Class<?> clazz, Object target, String methodName) {
        Method method = findMethod(clazz, methodName, new Class<?>[0]);
        return invokeMethod(method, target);
    }

    /**
     * 执行方法
     *
     * @param method 方法
     * @param target 实例对象
     * @return 执行方法的返回值
     */
    public static Object invokeMethod(Method method, Object target) {
        return invokeMethod(method, target, new Object[0]);
    }

    /**
     * 执行方法
     *
     * @param method 方法
     * @param target 实例对象
     * @param args   方法参数
     * @return 执行方法的返回值
     */
    public static Object invokeMethod(Method method, Object target, Object... args) {
        if (null == method) {
            throw new IllegalArgumentException("参数method是null");
        }
        try {
            return method.invoke(target, args);
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
        }
    }

    /**
     * Callback interface invoked on each field in the hierarchy.
     */
    public interface FieldCallback {

        /**
         * Perform an operation using the given field.
         *
         * @param field the field to operate on
         * @throws Exception Exception
         */
        void doWith(Field field) throws Exception;
    }

}
